package com.yizisu.basemvvm.utils

import android.app.Activity
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.AsyncTask
import com.yizisu.basemvvm.app
import java.math.BigDecimal
import java.math.RoundingMode
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util.*


/**
 * 若红楼梦空，亦初心不变
 * 作者：kotle
 * 包名：com.yizisu.basemvvm.utils
 * 时间：2019/1/17 23:52
 * 描述：其他工具类集合
 */
/**
 * 通用的错误捕获，默认不处理错误，只是防止崩溃
 */
fun tryError(
    handlerError: ((Throwable) -> Unit)? = null,
    finally: (() -> Unit)? = null,
    code: () -> Unit
) {
    try {
        code.invoke()
    } catch (e: Throwable) {
        e.printStackTrace()
        handlerError?.invoke(e)
    } finally {
        finally?.invoke()
    }
}

/**
 * 用AsyncTask代替线程，减少消耗
 * 虽然创建多个对象，但是他自己会用一个线程池
 * 一个对象只是一个任务
 */
class AsyncThread<Params, Progress, Result>(
    private val isSerial: Boolean = false/*是否按顺序一个一个执行任务*/,
    private val call: AsyncThreadCall<Progress, Result>? = null,
    private val run: (params: Array<out Params>) -> Result
) : AsyncTask<Params, Progress, Result>() {
    /**
     * 是否运行过
     */
    private var isHadRun = false

    override fun onProgressUpdate(values: Array<Progress>) {
        super.onProgressUpdate(*values)
        call?.onProgressUpdate(values)
    }

    override fun onPostExecute(result: Result) {
        super.onPostExecute(result)
        call?.onComplete(result)
    }

    override fun doInBackground(params: Array<out Params>): Result {
        return run.invoke(params)
    }

    override fun onCancelled(result: Result) {
        super.onCancelled(result)
        call?.onCancelled(result)
    }

    override fun onCancelled() {
        super.onCancelled()
        call?.onCancelled()
    }

    override fun onPreExecute() {
        super.onPreExecute()
        call?.onStart()
    }

    fun onError(error: Throwable) {
        call?.onError(error)
    }

    /**
     * 设置进度@{onProgressUpdate}会回调
     */
    fun setProgress(vararg progress: Progress) {
        publishProgress(*progress)
        call?.onProgressUpdateInIoThread(progress)
    }

    /**
     * 开启线程
     */
    fun start(vararg values: Params): AsyncTask<Params, Progress, Result> {
        if (isHadRun) {
            //AsyncTask只能运行一次，否则会报错
            return this
        }
        isHadRun = true
        return if (isSerial) {
            execute(*values)
        } else {
            executeOnExecutor(THREAD_POOL_EXECUTOR, *values)
        }
    }

    interface AsyncThreadCall<Progress, Result> {
        fun onProgressUpdate(values: Array<out Progress>) {
        }

        fun onProgressUpdateInIoThread(values: Array<out Progress>) {
        }

        fun onComplete(result: Result) {
        }

        fun onCancelled(result: Result) {
        }

        fun onCancelled() {
        }

        fun onError(error: Throwable) {

        }

        fun onStart() {
        }
    }
}


/**
 * 毫秒换成00:00:00
 */
fun getCountTimeByLong(finishTime: Long): String {
    var totalTime = (finishTime / 1000).toInt()//秒
    var hour = 0
    var minute = 0
    var second = 0

    if (3600 <= totalTime) {
        hour = totalTime / 3600
        totalTime -= 3600 * hour
    }
    return getCountTimeByLong(finishTime, hour > 0)
}

/**
 * 毫秒换成00:00:00
 */
fun getCountTimeByLong(finishTime: Long, isNeedHour: Boolean): String {
    var totalTime = (finishTime / 1000).toInt()//秒
    var hour = 0
    var minute = 0
    var second = 0

    if (3600 <= totalTime) {
        hour = totalTime / 3600
        totalTime -= 3600 * hour
    }
    if (60 <= totalTime) {
        minute = totalTime / 60
        totalTime -= 60 * minute
    }
    if (0 <= totalTime) {
        second = totalTime
    }
    val sb = StringBuilder()
    if (isNeedHour) {
        if (hour < 10) {
            sb.append("0").append(hour).append(":")
        } else {
            sb.append(hour).append(":")
        }
    }
    if (minute < 10) {
        sb.append("0").append(minute).append(":")
    } else {
        sb.append(minute).append(":")
    }
    if (second < 10) {
        sb.append("0").append(second)
    } else {
        sb.append(second)
    }
    return sb.toString()
}


/**时间戳转日期*/
fun longTimeToStr(time: Long?, pattern: String = "yyyy-MM-dd HH:mm"): String {
    if (time == null) {
        return ""
    }
    val format = SimpleDateFormat(pattern, Locale.getDefault())
    return format.format(time).toString()
}

/**年月日转时间戳*/
fun ymdToLongTime(year: Int, month: Int, day: Int, isFirst: Boolean): Long {
    val calendar = GregorianCalendar()
    if (isFirst) {
        calendar.set(year, month - 1, day, 0, 0)
    } else {
        calendar.set(year, month - 1, day, 23, 59)
    }
    return calendar.timeInMillis
}

/**年月日转时间戳*/
fun ymdHmToLongTime(year: Int, month: Int, day: Int, hourOfDay: Int, minute: Int): Long {
    val calendar = GregorianCalendar()
    calendar.set(year, month - 1, day, hourOfDay, minute)
    return calendar.timeInMillis
}

/**
 * 保留两位小数
 */
fun BigDecimal?.keepTwoPoint(roundingMode: RoundingMode = RoundingMode.HALF_EVEN): String {
    return try {
        this?.setScale(2, roundingMode)?.toString() ?: "0.00"
    } catch (e: Throwable) {
        "0.00"
    }
}

/**
 * 保留两位小数
 */
fun String?.keepTwoPoint(roundingMode: RoundingMode = RoundingMode.HALF_EVEN): String {
    return try {
        if (this == null) {
            "0.00"
        } else {
            BigDecimal(this).setScale(2, roundingMode)?.toString() ?: this
        }
    } catch (e: Throwable) {
        "0.00"
    }

}

/**
 * 判断某个对象是否是这个类型
 */
inline fun <reified Obj> Any?.isThis(isThis: Obj.() -> Unit) {
    if (this is Obj) {
        isThis(this)
    }
}

/**
 * 安全的类型转换
 */
inline fun <reified Obj> Any?.safeGet(): Obj? {
    return if (this is Obj) {
        this
    } else {
        null
    }
}

/**
 * 获取openSsl haskKey
 * 比如facebook的login需要这个
 */
fun getAppKeyHash(): MutableList<String> {
    val keyHashList = mutableListOf<String>()
    try {
        val info = app.packageManager.getPackageInfo(app.packageName, PackageManager.GET_SIGNATURES)
        info.signatures?.forEach { signature ->
            val md = MessageDigest.getInstance("SHA1")
            md.update(signature.toByteArray())
            val keyHash =
                android.util.Base64.encodeToString(md.digest(), android.util.Base64.DEFAULT)
            keyHashList.add(keyHash)
        }
    } catch (error: Throwable) {
        error.printStackTrace()
    } finally {
        return keyHashList
    }
}

/**
 *获取签名的sha1
 * 比如百度地图就需要这个
 */
fun getAppHA1(context: Context): MutableList<String>? {
    val shals = mutableListOf<String>()
    try {
        val info: PackageInfo = context.packageManager.getPackageInfo(
            context.packageName, PackageManager.GET_SIGNATURES
        )
        info.signatures?.forEach {
            val cert: ByteArray? = it.toByteArray()
            val md: MessageDigest = MessageDigest.getInstance("SHA1")
            val publicKey: ByteArray = md.digest(cert)
            val hexString = StringBuffer()
            for (i in publicKey.indices) {
                val appendString = Integer.toHexString(0xFF and publicKey[i].toInt())
                    .toUpperCase(Locale.US)
                if (appendString.length == 1) hexString.append("0")
                hexString.append(appendString)
                hexString.append(":")
            }
            val result = hexString.toString()
            val sha1 = result.substring(0, result.length - 1)
            shals.add(sha1)
        }
    } catch (e: Throwable) {
        e.printStackTrace()
    } finally {
        return shals
    }
}


/**
 * 比较两个字符串的相识度
 * 核心算法：用一个二维数组记录每个字符串是否相同，如果相同记为0，不相同记为1，每行每列相同个数累加
 * 则数组最后一个数为不相同的总数，从而判断这两个字符的相识度
 */
private fun compare(str: String, target: String): Int {
    val d: Array<IntArray> // 矩阵
    val n = str.length
    val m = target.length
    var i = 0 // 遍历str的
    var j: Int // 遍历target的
    var ch1: Char // str的
    var ch2: Char // target的
    var temp: Int // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
    if (n == 0) {
        return m
    }
    if (m == 0) {
        return n
    }
    d = Array(n + 1) { IntArray(m + 1) }
    // 初始化第一列
    while (i <= n) {
        d[i][0] = i
        i++
    }
    // 初始化第一行
    j = 0
    while (j <= m) {
        d[0][j] = j
        j++
    }
    i = 1
    while (i <= n) {
        // 遍历str
        ch1 = str[i - 1]
        // 去匹配target
        j = 1
        while (j <= m) {
            ch2 = target[j - 1]
            temp =
                if (ch1 == ch2 || ch1.toInt() == ch2.toInt() + 32 || ch1.toInt() + 32 == ch2.toInt()) {
                    0
                } else {
                    1
                }
            // 左边+1,上边+1, 左上角+temp取最小
            d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp)
            j++
        }
        i++
    }
    return d[n][m]
}


/**
 * 获取最小的值
 */
private fun min(oldOne: Int, two: Int, three: Int): Int {
    var one = oldOne
    return if ((if (one < two) one else two.also { one = it }) < three) one else three
}


/**
 * 获取两字符串的相似度
 */
fun getStringSimilarityRatio(str: String, target: String): Float {
    val max = str.length.coerceAtLeast(target.length)
    return 1 - compare(str, target).toFloat() / max
}